#pragma once
#include<iostream>
#include<pthread.h>
#include<queue>


template<class T>
class BlockQueue
{
    static const int defaultnum = 20;
public:
    BlockQueue(int maxcap = defaultnum)
        :maxcap_(maxcap)
    {
        pthread_mutex_init(&mutex_,nullptr);
        pthread_cond_init(&p_cond_,nullptr);
        pthread_cond_init(&c_cond_,nullptr);
        low_water_ = maxcap_ / 3;
        high_water_ = (maxcap_ *2)/3;
    }

    T pop()
    {

        pthread_mutex_lock(&mutex_);
        while(q_.size() == 0)            //判断临界资源是否满足,也是访问临界资源
        {
            pthread_cond_wait(&c_cond_,&mutex_);
        }
        T out = q_.front();
        q_.pop();

        if(q_.size() < low_water_)
            pthread_cond_signal(&p_cond_);
        pthread_mutex_unlock(&mutex_);
        return out;
    }

    void push(const T &in)
    {
        pthread_mutex_lock(&mutex_);
        while(q_.size() == maxcap_)              //while防止伪唤醒
        {
            pthread_cond_wait(&p_cond_,&mutex_);  //调用时候,自动释放锁
        }
        //队列未满
        q_.push(in);
        if(q_.size() > high_water_)
            pthread_cond_signal(&c_cond_);
        pthread_mutex_unlock(&mutex_);
    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&mutex_);
        pthread_cond_destroy(&c_cond_);
        pthread_cond_destroy(&p_cond_);
    }

private:
    std::queue<T> q_;    //共享资源
    int maxcap_;      //极值
    pthread_mutex_t mutex_;
    pthread_cond_t c_cond_;
    pthread_cond_t p_cond_;

    int high_water_;
    int low_water_;
};

